package com.jindi.jacococli.biz.config;

import com.jindi.jacococli.biz.constant.Constant;
import org.springframework.aop.Advisor;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.context.annotation.Bean;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionManager;
import org.springframework.transaction.interceptor.NameMatchTransactionAttributeSource;
import org.springframework.transaction.interceptor.RollbackRuleAttribute;
import org.springframework.transaction.interceptor.RuleBasedTransactionAttribute;
import org.springframework.transaction.interceptor.TransactionAttribute;
import org.springframework.transaction.interceptor.TransactionInterceptor;

import javax.annotation.Resource;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

//@Aspect
//@Configuration
public class TransactionalConfig {

    /**
     * 配置方法过期时间，默认-1,永不超时
     */
    private static final int METHOD_TIME_OUT = 3000;

    private static final String AOP_POINTCUT_EXPRESSION =
            "execution(public * com.jindi.jacococli.biz.business.manager..*.*(..))"
                    + "|| execution(public * com.jindi.jacococli.biz.business.action..*.*(..))"
                    + "|| execution(public * com.jindi.jacococli.biz.business.service..*.*(..))"
                    + "|| execution(public * com.jindi.jacococli.biz.business.mapper..*.*(..))";

    /**
     * 事务管理器
     */
    @Resource
    private TransactionManager transactionManager;

    @Bean
    public TransactionInterceptor txAdvice() {
        NameMatchTransactionAttributeSource source = new NameMatchTransactionAttributeSource();
        RuleBasedTransactionAttribute readOnly = new RuleBasedTransactionAttribute();
        readOnly.setReadOnly(true);
        readOnly.setPropagationBehavior(TransactionDefinition.PROPAGATION_NOT_SUPPORTED);
        RuleBasedTransactionAttribute required = new RuleBasedTransactionAttribute();
        required.setRollbackRules(Collections.singletonList(new RollbackRuleAttribute(Exception.class)));
        required.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
        required.setTimeout(METHOD_TIME_OUT);
        Map<String, TransactionAttribute> attributesMap = new HashMap<>(Constant.MAP_INITIAL_CAPACITY);
        attributesMap.put("add*", required);
        attributesMap.put("save*", required);
        attributesMap.put("insert*", required);
        attributesMap.put("update*", required);
        attributesMap.put("delete*", required);
        attributesMap.put("do*", required);
        attributesMap.put("batch*", required);
        // 只读事务，不做更新操作
        attributesMap.put("get*", readOnly);
        attributesMap.put("query*", readOnly);
        attributesMap.put("find*", readOnly);
        attributesMap.put("list*", readOnly);

        source.setNameMap(attributesMap);
        return new TransactionInterceptor(transactionManager, source);
    }

    /**
     * 设置切面=切点pointcut+通知TxAdvice
     */
    @Bean
    public Advisor txAdviceAdvisor() {
        AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
        pointcut.setExpression(AOP_POINTCUT_EXPRESSION);
        return new DefaultPointcutAdvisor(pointcut, txAdvice());
    }

}
